/**
XenSim simulates xenbal.
Copyright (C) 2006 Travis Vachon

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
package xensim;

import java.util.Collection;
import java.util.Vector;

public class Connection {
	SimGlobals globals;
	private long bandwidth;
	private long usedMigRxBandwidth;
	private long usedMigTxBandwidth;
	protected Vector<ERPair> txMigrationEvents;
	protected Vector<ERPair> rxMigrationEvents;
	private Collection<Domain> domains;
	
	/**
	 * 
	 * @param bandwidth bandwidth in bits/second
	 */
	public Connection(SimGlobals globals,long bandwidth, Collection<Domain> domains){
		this.globals = globals;
		this.bandwidth = bandwidth/SimGlobals.TIME_CONSTANT;
		this.domains = domains;
		usedMigRxBandwidth = 0;
		usedMigTxBandwidth = 0;
		txMigrationEvents = new Vector<ERPair>();
		rxMigrationEvents = new Vector<ERPair>();
		
	}
	
	protected long getBandwidth(){
		return bandwidth;
	}
	
	protected long getDomainTxBandwidth(){
		
		long domainBandwidth = 0;
		for(Domain domain: domains){
			domainBandwidth += domain.networkUsageFn.getOutRate(globals.currentTime);
		}
		return domainBandwidth;
	}
	
	protected long getDomainRxBandwidth(){
		long domainBandwidth = 0;
		for(Domain domain: domains){
			domainBandwidth += domain.networkUsageFn.getInRate(globals.currentTime);
		}
		return domainBandwidth;
	}
	
	protected long getUsedTxBandwidth(){
		return usedMigTxBandwidth + getDomainTxBandwidth();
	}
	
	protected long getUsedRxBandwidth(){
		return usedMigRxBandwidth + getDomainRxBandwidth();
	
	
	}
	
	/**
	 * 
	 * @return maximum transmit bandwidth that would be alloted to a NEW migration event
	 */
	protected long getMaxAvailTxBandwidth(){
		
		return (bandwidth - getDomainTxBandwidth())/(txMigrationEvents.size()+1);
	}
	
	/**
	 * 
	 * @return maximum transmit bandwidth that would be alloted to a NEW migration event
	 */
	protected long getMaxAvailRxBandwidth(){
		return (bandwidth - getDomainRxBandwidth())/(rxMigrationEvents.size()+1);
	}
	
	protected long requestTxBandwidth(MigrationQuantumEvent requestor, long request){
		txMigrationEvents.add(new ERPair(requestor,request));
		long domainBandwidth = getDomainTxBandwidth();
		if(bandwidth - domainBandwidth - usedMigTxBandwidth > request){
			requestor.usableBandwidth = request;
			usedMigTxBandwidth += request;
			return request;
		}
		else{
			usedMigTxBandwidth = 0;
			long maxBandwidthPerEvent = (bandwidth - domainBandwidth)/ txMigrationEvents.size();
			for(ERPair event: txMigrationEvents){
				event.event.usableBandwidth = Math.min(maxBandwidthPerEvent,event.request);
				usedMigTxBandwidth += Math.min(maxBandwidthPerEvent,event.request);
			}
			return Math.min(maxBandwidthPerEvent,request);
		}
	}
	
	protected long requestRxBandwidth(MigrationQuantumEvent requestor, long request){
		
		rxMigrationEvents.add(new ERPair(requestor,request));
		long domainBandwidth = getDomainRxBandwidth();
		if(bandwidth - usedMigRxBandwidth > request) {
			usedMigRxBandwidth += request;
			return request;
		}
		else{
			usedMigRxBandwidth = 0;
			long maxBandwidthPerEvent = (bandwidth - domainBandwidth)/ rxMigrationEvents.size();
			for(ERPair event: rxMigrationEvents){
				event.event.usableBandwidth = Math.min(maxBandwidthPerEvent,event.request);
				usedMigTxBandwidth += Math.min(maxBandwidthPerEvent,event.request);
			}
			return Math.min(maxBandwidthPerEvent,request);

		}
	}
	
	protected class ERPair{
		protected MigrationQuantumEvent event;
		protected long request;
		
		ERPair (MigrationQuantumEvent requestor, long request){
			event = requestor;
			this.request = request;
		}
	}

}
